package br.org.nomoney.vink.util.servlet.client;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.crypto.NoSuchMechanismException;

import br.org.nomoney.vink.util.serialize.ObjectToFromBytesConverter;
import br.org.nomoney.vink.util.servlet.io.ByteArrayUtil;

public class MethodCallerServletClient {

	private String servletUrlName;
	private ObjectToFromBytesConverter converter;

	public MethodCallerServletClient(String servletUrlName,
			ObjectToFromBytesConverter converter) {
		this.servletUrlName = servletUrlName;
		this.converter = converter;
	}

	public Object callMethod(String methodName, Object... args)
			throws Exception {
		Object result = null;

		// Verify method name
		if (methodName != null && !methodName.equals("")) {

			// Connect to server and send info
			HttpURLConnection urlConnection = null;
			try {
				urlConnection = connectToServer(methodName);
				OutputStream out = urlConnection.getOutputStream();

				// Write arguments to servlet
				byte[] argsAsBytes = this.converter.fromObjectToBytes(args);
				if (argsAsBytes != null) {
					out.write(argsAsBytes);
				}

				// Send Data!
				out.flush();
				out.close();

				if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
					// Read response from servlet
					InputStream is = urlConnection.getInputStream();
					int length = urlConnection.getContentLength();
					byte[] responseAsBytes = ByteArrayUtil
							.getByteArrayFromInput(length, is);
					result = this.converter.fromBytesToObject(responseAsBytes);

					// If result is a exception, throw it
					if (result instanceof Exception) {
						throw (Exception) result;
					}
				}

			} finally {
				if (urlConnection != null) {
					urlConnection.disconnect();
				}
			}
		} else {
			throw new NoSuchMechanismException(
					"Method name is invalid: null or empty.");
		}
		return result;
	}

	private HttpURLConnection connectToServer(String methodName)
			throws MalformedURLException, IOException {

		String urlName = this.servletUrlName + "?method=" + methodName;
		URL url = new URL(urlName);

		HttpURLConnection urlConnection = (HttpURLConnection) url
				.openConnection();
		urlConnection.setDoOutput(true);

		urlConnection.setRequestMethod("POST");
		urlConnection.setRequestProperty("Content-Type",
				"application/octet-stream");

		urlConnection.connect();
		return urlConnection;
	}

}
